#pragma once

class ADTChunk;

class ADTModel : public ModelBase
{
	MHDR m_header;
	std::string m_fileName;
	CMpqFile* m_file;
	ui32 LoadChunk(ui32& sig, ui32& len);
	std::vector<ADTMapChunk> m_chunkOfs;
	std::vector<ADTChunk*> m_chunks;
	std::vector<std::string> m_textures;
	std::map<ui32, std::string> m_doodads, m_wmos;
	std::vector<ui32> m_doodadrefs, m_wmorefs;
	std::map<ui32, MDDF> m_mddf;
	std::map<ui32, ADTDoodadEntry> mDoodads;
	std::vector<MODF> m_modf;
	WDTHeader* m_pHeader;
	LiquidHandler* m_pHandler;
	ADTLoader mLoader;

	std::map<ui32, WMOModel*> m_wmoModels;
	std::map<ui32, M2Model*> m_doodModels;

	ui32 m_chunksLoaded;

	void LoadDoodads();
	void LoadDoodadRefs();
	void LoadDoodadPlacement();
	void LoadWmos();
	void LoadWmoRefs();
	void LoadWmoPlacement();

	FileBuffer* m_buffer;

	ADTTextureBlock m_textureBlock;

	void LoadM2Model(ui32 uid);

public:
	ADTModel(std::string szName);
	bool Init(bool initial = false);
	void Deinit();
	void Draw(Vertex3F pos, Vertex3F tar);
	std::string GetTexture(ui32 position) { if(position >= m_textures.size()) return ""; return m_textures[position]; }
	bool Intersect(D3DXVECTOR3& rayO, D3DXVECTOR3& rayDir, float* pOut);
	void RecalcOffsets(ui32 pos, i32 change);
	void loadDoodad(ui32 refId);

	void changeDoodadPosition(ui32 id, const Vertex3F& newPos);

	ADTTextureBlock& GetTextureBlock() { return m_textureBlock; }

	void LoadModel(ui32 uniqueId)
	{
		if(m_doodModels[uniqueId])
			return;
		LoadM2Model(uniqueId);
	}

	WDTHeader* GetWdtHeader() { return m_pHeader; }
	void SetWdtHeader(WDTHeader* pHeader) { m_pHeader = pHeader; }

	std::vector<std::string> GetTextures() { return m_textures; }

	std::string GetFileName() { return m_fileName; }

	void UpdateSizes(i32 mod, ui32 offset)
	{
		for(ui32 i = 0; i < m_chunkOfs.size(); ++i)
		{
			if(m_chunkOfs[i].offset == offset)
				m_chunkOfs[i].size += mod;
		}
		m_buffer->Write(m_header.ofsMCIN + 0x14 + 0x8, 256 * sizeof(ADTMapChunk), &m_chunkOfs[0]);
	}

	ADTChunk* GetChunk(ui32 x, ui32 y)
	{
		ui32 tot = y * 16 + x;
		if(tot >= m_chunks.size())
			return 0;
		return m_chunks[tot];
	}

	void ChangeHeight(Vertex3F pos, float radius, float amount, ui32 type);
	void FlattenHeight(Vertex3F pos, float radius, float amount, ui32 type);
	void BlurHeight(Vertex3F pos, float radius, float amount, ui32 type);

	void TextureTerrain(Vertex3F pos, float radius, float amount, ui32 type, Texture* tex, ui32 brush)
	{
		for(ui32 i = 0; i < 256; ++i)
			m_chunks[i]->ChangeTexture(pos, radius, amount, type, tex, brush);
	}

	void Save();

	ui32 AddTexture(std::string szTexture);

	void ChangeMCCV(ui8 a, ui8 r, ui8 g, ui8 b, Vertex3F point, float radius)
	{
		for(ui32 i = 0; i < 256; ++i)
			m_chunks[i]->DrawMCCV(a, r, g, b, point, radius);
	}

	void ToggleHole(Vertex3F pos)
	{
		for(ui32 i = 0; i < 256; ++i)
			m_chunks[i]->ToggleHole(pos);
	}

	void DrawShadow(Vertex3F pos, float radius, bool on)
	{
		for(ui32 i = 0; i < 256; ++i)
			m_chunks[i]->DrawShadow(pos, radius, on);
	}

	void BeforeReset()
	{
		for(ui32 i = 0; i < 256; ++i)
			m_chunks[i]->BeforeReset();
	}

	void OnReset()
	{
		for(ui32 i = 0; i < 256; ++i)
			m_chunks[i]->OnReset();
	}

	void AddMTFX();

	ui32 m_indexX, m_indexZ;

	ui32 AddM2Model(std::string szName);
	ui32 AddWMOModel(std::string szName);
	ui32 CreateWmoId(ui32 wmoNum);
	ui32 CreateMODF(ui32 wmoId, Vertex3F position);

	M2Model* GetDoodad(ui32 unique) { return m_doodModels[unique]; }

	void UpdateMDXPosition(ADTModel* pBaseMap, ui32 doodad, float x, float y, float z)
	{
		for(ui32 i = 0; i < 256; ++i)
			m_chunks[i]->UpdateMDXPosition(pBaseMap, doodad, x, y, z);
	}

	void Update(ui32 diff);
	void RedoNormals() {
		for(ui32 i = 0; i < 256; ++i)
			m_chunks[i]->RedoNormals();
	}

	ADTLoader& getSyncLoader() { return mLoader; }
};